# Yacc example

import ply.yacc as yacc

# Get the token map from the lexer.  This is required.
from asm_lexer import tokens, lexer
from assembler import Code, SymTable


class code_content:
    A_INSTRUCTION = 1
    C_INSTRUCTION = 2
    L_INSTRUCTION = 3

    def __init__(self):
        self.type = self.A_INSTRUCTION
        # a instruction
        self.a_is_number = 0
        self.a_number = 0
        self.a_label = ''
        # l instruction
        self.l_label = ''
        # c instruction
        self.c_comp = ''
        self.c_dest = ''
        self.c_jump = ''


def p_all_expr(p):
    '''all_expr : a_expr
                | c_expr
                | l_expr'''
    p[0] = p[1]

# a_expr


def p_a_instruction(p):
    'a_expr : AT a_term'
    p[0] = p[2]


def p_a_instruction_number(p):
    'a_term : NUMBER'
    code = code_content()
    code.type = code_content.A_INSTRUCTION
    code.a_is_number = 1
    code.a_number = p[1]
    p[0] = code


def p_a_instruction_label(p):
    'a_term : LABEL'
    code = code_content()
    code.type = code_content.A_INSTRUCTION
    code.a_is_number = 0
    code.a_label = p[1]
    p[0] = code

# l_expr


def p_label_expr(p):
    'l_expr : LPAREN LABEL RPAREN'
    code = code_content()
    code.type = code_content.L_INSTRUCTION
    code.l_label = p[2]
    p[0] = code

# c_expr
# dest=comp;jump
# comp;jump
# dest=comp


def p_c_expr_1(p):
    'c_expr : c_dest EQUAL c_comp SEMICOLON JMP'
    code = code_content()
    code.type = code_content.C_INSTRUCTION
    code.c_dest = p[1]
    code.c_comp = p[3]
    code.c_jump = p[5]
    p[0] = code


def p_c_expr_2(p):
    'c_expr : c_comp SEMICOLON JMP'
    code = code_content()
    code.type = code_content.C_INSTRUCTION
    code.c_dest = ""
    code.c_comp = p[1]
    code.c_jump = p[3]
    p[0] = code


def p_c_expr_3(p):
    'c_expr : c_dest EQUAL c_comp'
    code = code_content()
    code.type = code_content.C_INSTRUCTION
    code.c_dest = p[1]
    code.c_comp = p[3]
    code.c_jump = ""
    p[0] = code


def p_c_dest_1(p):
    'c_dest : ID c_dest '
    p[0] = ''.join(p[1:])


def p_c_dest_2(p):
    'c_dest : ID'
    p[0] = p[1]


def p_c_comp_1(p):
    'c_comp : ID'
    p[0] = p[1]


def p_c_comp_2(p):
    '''c_comp : ID PLUS ID
            | ID MINUS ID
            | ID AND ID
            | ID OR ID
            | NOT ID
            | MINUS ID
            | NUMBER
            | MINUS NUMBER
            | ID PLUS NUMBER
            | ID MINUS NUMBER
    '''
    p[0] = ''.join([str(n) for n in p[1:]])

# Error rule for syntax errors


def p_error(p):
    if parser.token():
        print("Syntax error in input!")
        exit(1)
    else:
        pass


# Build the parser
parser = yacc.yacc()

if __name__ == "__main__":
    s = '''@234
    //Hello
    @LABEL1 //Hello
    (LABEL1)
    AM=D+M;JMP
    @ARG
    '''
    for line in s.split():
        ret: code_content = parser.parse(line, lexer=lexer)
        if ret:
            print(ret.type)
